<template>
  <span v-bind="$attrs">
    <slot name="prefix"></slot>
    <span class="valueNum"> {{ formattedNumber }}</span>
    <span class="unit">{{ unit }}</span>
    <slot name="suffix"></slot>
  </span>
</template>

<script lang="ts" setup>
import { ref, watch, computed, onMounted } from 'vue'

interface Props {
  value: number
  unit: string
  duration?: number
  decimals?: number
  separator?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  duration: 1000,
  decimals: undefined, // 改为 undefined 以支持自动检测
  separator: false,
})

const currentValue = ref(0)
let startTime: number | null = null
let hasAnimated = false

// 自动检测小数位数
const actualDecimals = computed(() => {
  if (props.decimals !== undefined) return props.decimals
  const str = (props.value || 0).toString()
  const dotIndex = str.indexOf('.')
  return dotIndex === -1 ? 0 : str.length - dotIndex - 1
})

const formattedNumber = computed(() => {
  return props.separator
    ? currentValue.value.toLocaleString(undefined, {
        minimumFractionDigits: actualDecimals.value,
        maximumFractionDigits: actualDecimals.value,
      })
    : Number.isInteger(currentValue.value)
      ? currentValue.value.toString()
      : (currentValue.value || 0).toFixed(actualDecimals.value)
})

watch(
  () => props.value,
  (newValue) => {
    if (!hasAnimated) {
      hasAnimated = true
      animateValue(0, newValue, props.duration)
    } else {
      animateValue(currentValue.value, newValue, props.duration)
    }
  },
)

onMounted(() => {
  animateValue(0, props.value, props.duration)
})

const animateValue = (start: number, end: number, duration: number) => {
  startTime = null
  const step = (timestamp: number) => {
    if (!startTime) startTime = timestamp
    const progress = Math.min((timestamp - startTime) / duration, 1)

    // 直接保留原始精度，仅在最后格式化
    const rawValue = start + (end - start) * progress

    // 动画过程中保留3位小数精度
    currentValue.value = Number(rawValue.toFixed(3))

    if (progress < 1) {
      requestAnimationFrame(step)
    } else {
      // 动画结束时强制精确赋值
      currentValue.value = end
    }
  }

  requestAnimationFrame(step)
}
</script>
<style scoped>
.unit {
  font-size: 12px;
  color: #999999;
  margin-left: 5px;
}
.valueNum {
  color: #666666;
}
</style>
